﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Security;

using View.BookForms;
using View.LibrarianForms;
using View.MemberForms;

using Model;
using Model.DataManagement;
using Model.Entity;
using Model.Entity.Members;

namespace View
{


    public partial class MainForm : Form
    {
        private static readonly IDictionary<string, int> _memberTypeMap =
            new Dictionary<string, int> { 
            { "Egyetemi hallgat\u00F3", 1 }, 
            { "Egyetemi oktat\u00F3", 2 }, 
            { "M\u00E1sik egyetem polg\u00E1ra", 3 }, 
            { "Egy\u00E9b", 4 } };

        private ILibraryModel _model;

        private BookSearchForm _bookSearchForm;
        private BookPicker _bookPicker;
        private BookEditForm _bookEditForm;
        private IList<Model.Entity.Book> _books;
        private IList<Borrowing> _pendingNewBorrowings;
        private IList<Borrowing> _pendingReturnedBorrowings;

        private LibrarianEditForm _librarianEditForm;
        private IList<Model.Entity.Librarian> _librarians;

        private MemberEditForm _memberEditForm;
        private Int32 _editedMemberId;
        private Member _editedMember;
        private IList<Borrowing> _returnedBrs;
        private IList<Borrowing> _newBrs;
        private IList<Model.Entity.Members.Member> _members;

        private LoginForm _loginForm;

        public MainForm()
        {
            InitializeComponent();
            _model = new LibraryModel();
            _model.Feedback += Model_Feedback;
            _model.Init();
            //_model.ResetDatamodel();

            _loginForm = new LoginForm();
            _loginForm.Submit += LoginForm_Submit;
            _loginForm.Shown += LoginForm_Shown;
            _loginForm.FormClosing += LoginForm_Hide;
            _loginForm.Exit += LoginForm_Exit;

            _bookSearchForm = new BookSearchForm();
            _bookSearchForm.Submit += BookSearchForm_Submit;
            _bookPicker = new BookPicker();
            _bookPicker.Submit += BookPicker_Submit;
            _bookEditForm = new BookEditForm();
            _bookEditForm.Submit += BookEditForm_Submit;

            _librarianEditForm = new LibrarianEditForm();

            _memberEditForm = new MemberEditForm();
            _memberEditForm.Submit += MemberEditForm_Submit;
            _memberEditForm.Cancel += MemberEditForm_Cancel;
            _memberEditForm.NewBurrow += MemberEditForm_NewBorrowing;
            _memberEditForm.ReturnBook += MemberEditForm_ReturnBook;

            _books = new List<Model.Entity.Book>();
            _members = new List<Model.Entity.Members.Member>();
            _librarians = new List<Model.Entity.Librarian>();

            _pendingReturnedBorrowings = new List<Borrowing>();
            _pendingNewBorrowings = new List<Borrowing>();

            dataGridViewBooks.DataSource = _books;
            dataGridViewLibrarians.DataSource = _librarians;
            dataGridViewMembers.DataSource = _members;

        }

        /*
         * Private methods
         */

        private void InitWorkspace()
        {
            UpdateBooks();
            UpdateMembers();
            var pages = tabControlEntities.TabPages;
            try
            {
                UpdateLibrarians();
                if (!pages.Contains(tabPageLibrarians))
                {
                    pages.Add(tabPageLibrarians);
                }
            }
            catch (SecurityException)
            {
                if (pages.Contains(tabPageLibrarians))
                {
                    pages.Remove(tabPageLibrarians);
                }
            }
        }

        private void UpdateBooks(IList<Book> books = null)
        {
            books = books ?? _model.GetAllBooks();
            //dataGridViewBooks.AutoGenerateColumns = false;
            dataGridViewBooks.DataSource = books.Select(m => new
            {
                Id = m.GetId().ToString(),
                SimpleId = (m.SimpleId ?? ""),
                Author = (m.Author ?? ""),
                Title = (m.Title ?? ""),
                Publisher = (m.Publisher ?? ""),
                Year = ((m.Year != null) ? m.Year.Value.Year.ToString() : ""),
                Edition = ((m.Edition != null) ? m.Edition.ToString() : ""),
                Isbn = (m.Isbn ?? ""),
                Borrowed = ((m.Borrowings.Any(b => (null == b.ReturnedDate)) ? "Igen" : "Nem")),
                Borrowings = ("brws"),
                Borrowable = ((m.Borrowable) ? "Igen" : "Nem")
            }).ToList();
        }

        private void UpdateBookPickerBooks(IList<Book> books = null)
        {
            books = books ?? _model.GetAllBooks();
            //dataGridViewBooks.AutoGenerateColumns = false;
            _bookPicker.dataGridViewBooks.DataSource = books.Select(m => new
            {
                Id = m.GetId().ToString(),
                SimpleId = (m.SimpleId ?? ""),
                Author = (m.Author ?? ""),
                Title = (m.Title ?? ""),
                Publisher = (m.Publisher ?? ""),
                Year = ((m.Year != null) ? m.Year.Value.Year.ToString() : ""),
                Edition = ((m.Edition != null) ? m.Edition.ToString() : ""),
                Isbn = (m.Isbn ?? ""),
                Borrowed = ((m.Borrowings.Any(b => (null == b.ReturnedDate)) ? "Igen" : "Nem")),
                Borrowings = ("brws"),
                Borrowable = ((m.Borrowable) ? "Igen" : "Nem")
            }).ToList();
        }

        private void UpdateBorrowings()
        {
            var _editedMember = _model.GetAllMembers().First(m => (m.GetId() == _editedMemberId));
            _memberEditForm.dataGridViewBorrowings.DataSource = _editedMember.Borrowings.Select(m => new
            {
                Id = m.GetId().ToString(),
                BookId = m.Book.GetId().ToString(),
                Author = (m.Book.Author ?? ""),
                Title = (m.Book.Title ?? ""),
                BorrowingDate = (m.BorrowedDate.Value.ToShortDateString()),
                ReturnDate = ((m.ReturnedDate != null) ? m.ReturnedDate.Value.ToShortDateString() : ""),
                Deadline = (m.BorrowedDate + _editedMember.GetBorrowDurationLimit())
            }).ToList();
            //_memberEditForm.dataGridViewBorrowings.DataSource = _editedMember.Borrowings.Select(m => new
            //{
            //    Id = m.GetId().ToString(),
            //    Author = (m.Book.Author ?? ""),
            //    Title = (m.Book.Title ?? ""),
            //    BorrowingDate = (m.BorrowedDate.Value.ToShortDateString()),
            //    ReturnDate = ((m.ReturnedDate != null) ? m.ReturnedDate.Value.ToShortDateString() : ""),
            //    Deadline = (m.BorrowedDate + _editedMember.GetBorrowDurationLimit())
            //}).ToList();
        }



        private void UpdateMembers(IList<Member> members = null)
        {
            members = members ?? _model.GetAllMembers();
            //dataGridViewBooks.AutoGenerateColumns = false;
            dataGridViewMembers.DataSource = members.Select(m => new
            {
                Id = m.GetId().ToString(),
                Name = (m.Name ?? ""),
                Address = (m.Address ?? ""),
                Contact = (m.Contact ?? ""),
                TypeString = (m.GetTypeString()),
                TypeId = (_memberTypeMap[m.GetTypeString()]),
                Borrowings = ""
            }).ToList();
        }

        private void UpdateLibrarians(IList<Librarian> members = null)
        {
            members = members ?? _model.GetAllLibrarians();
            //dataGridViewBooks.AutoGenerateColumns = false;
            dataGridViewLibrarians.DataSource = members.Select(m => new
            {
                Id = m.GetId().ToString(),
                Name = (m.Name ?? ""),
                Address = (m.Address ?? ""),
                Contact = (m.Phone ?? ""),
                Username = (m.Username),
                IsAdmin = ((m.IsAdmin) ? "Igen" : "Nem")
            }).ToList();
        }

        /*
         * Internal event handlers
         */

        private void Model_Feedback(object sender, FeedbackEventArgs args)
        {
            //MessageBox.Show(FormatMessages(args.Messages));
            MessageBox.Show(string.Join("\n", args.Messages.MessageList));
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            _model.TearDown();
        }

        private void menuItemExit_Click(object sender, EventArgs e)
        {

            if (null == _model.GetLoggedinUser())
            {
                _model.TearDown();
            }
            else
            {
                _model.Logout();
            }
            Close();
        }

        private void menuItemLogout_Click(object sender, EventArgs e)
        {
            _model.Logout();
            tabControlEntities.Hide();
            menuItemLogin.Enabled = true;
            menuItemLogout.Enabled = false;
            _loginForm.ShowDialog(new LoginEventArgs());
        }

        private void menuItemLogin_Click(object sender, EventArgs e)
        {
            _loginForm.ShowDialog(new LoginEventArgs());
            menuItemLogin.Enabled = false;
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            _loginForm.ShowDialog(new LoginEventArgs());
        }

        //
        // LoginForm
        //

        private void LoginForm_Exit(object sender, EventArgs args)
        {
            _model.TearDown();
            Close();
        }

        private void LoginForm_Shown(object sender, EventArgs args)
        {
            _loginForm.Activate();
        }

        private void LoginForm_Submit(object sender, LoginEventArgs args)
        {
            if (_model.Login(args.Username, args.Password))
            {
                _loginForm.SafeClose();
                tabControlEntities.Show();
                menuItemLogin.Enabled = false;
                menuItemLogout.Enabled = true;
                InitWorkspace();
            }
        }

        private void LoginForm_Hide(object sender, EventArgs whocares)
        {
            menuItemLogin.Enabled = true;
        }

        //
        // Book
        //

        private void buttonSearchBook_Click(object sender, EventArgs e)
        {
            _bookSearchForm.ShowDialog(new BookEventArgs());
        }

        private void buttonNewBook_Click(object sender, EventArgs e)
        {
            _bookEditForm.ShowDialog(new BookEventArgs());
        }

        private void buttonListBooks_Click(object sender, EventArgs e)
        {
            UpdateBooks();
        }

        private void buttonDeleteBook_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dataGridViewBooks.SelectedRows.Count; i++)
            {
                Int32? id = Int32.Parse(dataGridViewBooks.SelectedRows[i].Cells["ColumnId"].Value.ToString());
                _model.DeleteEntity(new Book(id));
            }
            UpdateBooks();
        }

        private void BookEditForm_Submit(object sender, BookEventArgs e)
        {
            Book book = new Book(e.Id, e.Author, e.Title, e.Publisher,
                new DateTime((int) e.Year, 1, 1), e.Edition, e.Isbn, e.SimpleId, e.Borrowable);
            _model.SaveEntity(book);
            UpdateBooks(_model.GetAllBooks());
        }

        private void BookSearchForm_Submit(object sender, BookEventArgs e)
        {
            Book book = new Book(e.Id, e.Author, e.Title, e.Publisher,
                null, e.Edition, e.Isbn, e.SimpleId, e.Borrowable);
            UpdateBooks(_model.FindBook(book));
        }

        //
        // Librarian
        //
        private void buttonListLibrarians_Click(object sender, EventArgs e)
        {
            UpdateLibrarians();
        }

        private void buttonDeleteLibrarian_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dataGridViewLibrarians.SelectedRows.Count; i++)
            {
                Int32? id = Int32.Parse(dataGridViewLibrarians.SelectedRows[i].Cells["LColumnId"].Value.ToString());
                _model.DeleteEntity(new Librarian(id));
            }
            UpdateLibrarians();
        }

        private void buttonEditLibrarian_Click(object sender, EventArgs e)
        {
            var row = dataGridViewLibrarians.SelectedRows[0];

            _librarianEditForm.ShowDialog(new LibrarianEventArgs(
                int.Parse(row.Cells["LColumnId"].Value.ToString()),
                row.Cells["ColumnName"].Value.ToString(),
                row.Cells["ColumnAddress"].Value.ToString(),
                row.Cells["LPhone"].Value.ToString(),
                (row.Cells["ColumnIsAdmin"].Value.ToString() == "Igen") ? true : false));


        }

        private void buttonNewLibrarian_Click(object sender, EventArgs e)
        {
            _librarianEditForm.ShowDialog(new LibrarianEventArgs());
        }

        private void LibrarianEditForm_Submit(object sender, LibrarianEventArgs args)
        {
        }

        //
        // Member
        //
        private void buttonListMembers_Click(object sender, EventArgs e)
        {
            UpdateMembers();
        }

        private void buttonDeleteMember_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < dataGridViewMembers.SelectedRows.Count; i++)
            {
                Int32? id = Int32.Parse(dataGridViewMembers.SelectedRows[i].Cells["MColumnId"].Value.ToString());
                _model.DeleteEntity(new Other(id));
            }
            UpdateMembers();
        }

        private void buttonEditMember_Click(object sender, EventArgs e)
        {
            var row = dataGridViewMembers.SelectedRows[0];
            _editedMemberId = Int32.Parse(row.Cells["MColumnId"].Value.ToString());

            _memberEditForm.ShowDialog(_model, new MemberEventArgs(
                _editedMemberId,
                row.Cells["MColumnName"].Value.ToString(),
                row.Cells["MColumnAddress"].Value.ToString(),
                row.Cells["MColumnContact"].Value.ToString(),
                int.Parse(row.Cells["MTypeId"].Value.ToString()) - 1));

        }

        private void buttonNewMember_Click(object sender, EventArgs e)
        {
            _memberEditForm.ShowDialog(_model, new MemberEventArgs());
        }

        private void MemberEditForm_NewBorrowing(object sender, EventArgs args)
        {
            UpdateBookPickerBooks();

            _editedMember = _model.GetAllMembers().First(m => m.GetId() == _editedMemberId);
            if (_editedMember.GetActiveBorrowLimit() <=
                _model.GetAllBorrowings().Count(b =>
                    (b.Member.GetId() == _editedMemberId && b.ReturnedDate == null)))
            {
                MessageBox.Show("El\u00E9rte a maxim\u00E1lis k\u00F6lcs\u00F6nz\u00E9si limitet!");
                return;
            }

            _bookPicker.ShowDialog();
        }

        private void MemberEditForm_Submit(object sender, MemberEventArgs args)
        {
            Member m = null;
            switch ((int) args.Type)
            {
                case 0:
                    m = new LocalStudent(args.Id, args.Name, args.Address, args.Contact);
                    break;

                case 1:
                    m = new LocalTeacher(args.Id, args.Name, args.Address, args.Contact);
                    break;

                case 2:
                    m = new ForeignUniMember(args.Id, args.Name, args.Address, args.Contact);
                    break;

                case 3:
                    m = new Other(args.Id, args.Name, args.Address, args.Contact);
                    break;

            }
            _model.SaveEntity(m);

            if (args.Id != null)
            {
                Member saved = _model.GetAllMembers().First(s => (s.GetId() == _editedMemberId));
                foreach (Borrowing pn in _pendingNewBorrowings)
                {
                    saved.AddBorrowing(pn);
                    _model.SaveEntity(pn);
                }
                _pendingNewBorrowings.Clear();
                foreach (Borrowing pn in _pendingReturnedBorrowings)
                {
                    pn.ReturnedDate = null;
                    _model.SaveEntity(pn);
                }
                _pendingReturnedBorrowings.Clear();
            }
            UpdateMembers();
            _editedMemberId = -1;
        }

        private void MemberEditForm_ReturnBook(object sender, BorrowingEventArgs args)
        {
            if (_editedMemberId < 1)
            {
                throw new InvalidOperationException("no edited member");
            }

            Borrowing br = _model.GetAllBorrowings().First(b => (b.GetId() == args.Id));
            //br.BorrowedDate = DateTime.Now - new TimeSpan(20, 0, 0, 0);
            Member m = br.Member;
            _model.SaveEntity(br);
            if (br.BorrowedDate + m.GetBorrowDurationLimit() < br.ReturnedDate)
            {
                MessageBox.Show("A k\u00F6nyv visszahozatala t\u00FAll\u00E9pte a hat\u00E1rid\u0151t!");
            }

            //Book returned = _model.GetAllBooks().First(b => (b.GetId() == args.Id));
            //Borrowing br = returned.Borrowings.First(
            //    b => (b.Member.GetId() == _editedMemberId));
            //if (br.ReturnedDate == null)
            //{
            //    _model.SaveEntity(br);
            //}
            //_pendingReturnedBorrowings.Add(br);
        }

        private void MemberEditForm_Cancel(object sender, EventArgs e)
        {
            //foreach (var b in _pendingNewBorrowings)
            //{
            //    _editedMember.RemoveBorrowing(b);
            //}
            //_pendingNewBorrowings.Clear();
            //_pendingReturnedBorrowings.Clear();
            Close();
        }

        private void BookPicker_Submit(object sender, BookEventArgs args)
        {
            _editedMember = _model.GetAllMembers().First(m => m.GetId() == _editedMemberId);
            //if (_editedMember.GetActiveBorrowLimit() <= 
            //    _model.GetAllBorrowings().Count(b => 
            //        (b.Member.GetId() == _editedMemberId && b.ReturnedDate == null)))
            //{
            //    MessageBox.Show("El\u00E9rte a maxim\u00E1lis k\u00F6lcs\u00F6nz\u00E9si limitet!");
            //    return;
            //} 
            if (args != null)
            {
                Book picked = _model.GetAllBooks().First(item => (item.GetId() == args.Id));
                Borrowing pending = new Borrowing(null, _editedMember, picked, DateTime.Now, null);
                _editedMember.AddBorrowing(pending);
                _model.SaveEntity(pending);
                //_pendingNewBorrowings.Add(pending);
            }
            UpdateBorrowings();
        }

    }
}
